package com.app.game.control;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;

import com.app.ThreadManager;
import com.app.game.chat.Message;
import com.app.game.other.AiPlayerFasade;
import com.app.game.other.Player;
import com.app.game.other.PlayerFix;
import com.app.observers.ClientObserver;
import com.app.server.ClientHandler;
import com.app.task.Task;
import com.app.task.TaskWatcher;
import com.app.task.WaitingTask;

public class NetworkHostGameController implements HostGameController,
		ClientObserver, TaskWatcher {

	private List<ClientHandler> clients = Collections
			.synchronizedList(new ArrayList<ClientHandler>());
	private ConcurrentHashMap<Integer, Player> playerList = new ConcurrentHashMap<Integer, Player>();
	private ConcurrentHashMap<Integer, Boolean> ready = new ConcurrentHashMap<Integer, Boolean>();
	//private ArrayList<PlayerFix> updates = new ArrayList<>();

	private AiPlayerFasade computers;
	private WaitingTask waitReadyTask = new WaitingTask(),
			waitRoundDoneTask = new WaitingTask();
	

	public NetworkHostGameController() {
		this(false);
	}

	public NetworkHostGameController(boolean local) {

		if (local) {
			computers = new AiPlayerFasade();
		}
		waitReadyTask.addTaskWatcher(this);
		waitRoundDoneTask.addTaskWatcher(this);
	}

	@Override
	public void doSpin() {
		Random random = new Random();
		Integer result = random.nextInt(37);
		for (ClientHandler client : clients) {
			client.sendResult(result);
		}
		if (computers != null) {
			computers.checkRes(result);
		}

	}

	@Override
	public void waitPlayersReady() {
		waitReadyTask.setTargetValue(clients.size());
		waitReadyTask.resetCurrentValue();
		ThreadManager.getInstance().execute(waitReadyTask);
	}

	@Override
	public void waitRoundDone() {
		waitRoundDoneTask.setTargetValue(playerList.size());
		waitRoundDoneTask.resetCurrentValue();
		ThreadManager.getInstance().execute(waitRoundDoneTask);
	}

	@Override
	public void startGame() {
		for (ClientHandler client : clients) {
			client.sendGameIsStarting();
		}
		// gameover = false;
		waitRoundDone();
	}

	@Override
	public void finishGame() {
		for (ClientHandler client : clients) {
			client.sendGameIsEnding();
		}
		waitReadyTask.stop();
		waitRoundDoneTask.stop();
	}

	@Override
	public void addClient(ClientHandler client) {
		client.registerObserver(this);
		clients.add(client);
		ThreadManager.getInstance().execute(client);
	}

	@Override
	public void updatePlayer(Player player, Integer id) {
		playerList.put(id, player);
		if (!ready.containsKey(id))
			ready.put(id, Boolean.FALSE);
		HashMap<Integer, Player> localList = new HashMap<Integer, Player>();
		Set<Entry<Integer, Player>> set = playerList.entrySet();
		Iterator<Entry<Integer, Player>> it = set.iterator();
		while (it.hasNext()) {
			Entry<Integer, Player> entry = it.next();
			localList.put(entry.getKey(), entry.getValue());
		}
		if (computers != null) {
			HashMap<Integer, Player> computPlayers = computers.getPlayers();
			localList.putAll(computPlayers);
		}
		try{
		Thread.sleep(2000);
		}catch(Exception e){
			
		}
		synchronized(NetworkHostGameController.class){
		
			for (ClientHandler client : clients) {
			client.sendPlayerlist(localList);
		}
		}
		Set s = ready.entrySet();
		Iterator i = s.iterator();
		while (i.hasNext()) {
			Entry<Integer, Boolean> entry = (Entry<Integer, Boolean>) i.next();
			if (entry.getValue()) {
				for (ClientHandler client : clients) {
					client.sendReadyNotification(entry.getKey());
				}
			}
		}
		waitReadyTask.stop();

		if (computers != null) {
			if (playerList.size() > 1) {
				waitReadyTask.setTargetValue(playerList.size());
			} else {
				waitReadyTask.setTargetValue(1);
			}
		} else {
			if (playerList.size() > 2) {
				waitReadyTask.setTargetValue(playerList.size());
			} else {
				waitReadyTask.setTargetValue(2);
			}
		}

		ThreadManager.getInstance().execute(waitReadyTask);
	}

	@Override
	public void updateMessage(Message msg) {

		for (ClientHandler client : clients) {
			client.sendMessage(msg);
		}

	}

	@Override
	public void updateReady(Integer playerId) {
		// readyPlayers++;
		ready.put(playerId, Boolean.TRUE);
		waitReadyTask.incrementCurrentValue();
		for (ClientHandler client : clients) {
			client.sendReadyNotification(playerId);
		}

	}

	@Override
	public void updateRoundDone(Integer playerId) {
		// roundsDone++;
		waitRoundDoneTask.incrementCurrentValue();
		for (ClientHandler client : clients) {
			client.sendRoundDoneNotification(playerId);
		}

	}

	@Override
	public synchronized void taskComplete(Task task) {
		if (task == waitReadyTask) {
			startGame();

		} else if (task == waitRoundDoneTask) {
			if (computers != null) {
				computers.pretendBets();
			}
			doSpin();
			waitRoundDone();
		}

	}

	@Override
	public synchronized void reupdatePlayer(PlayerFix player) {
		
		
		
		for (ClientHandler handler : clients) {
			
			if(computers!=null){
				
				for(PlayerFix pf : computers.getUpdates())
				handler.sendUpdatedPlayer(pf);
				
			}
				handler.sendUpdatedPlayer(player);
			
			int idh = handler.getId();
			int idp = player.getId();
			if (idh==idp){
				if(player.getValue() <= 0) {
			
				handler.sendGameIsEnding();
				clients.remove(handler);
			}
		}
		}
		
		
		if (computers == null) {
			if (clients.size() == 1) {
				finishGame();
			}
		} else if (clients.size() == 1
				&& computers.getActiveComputersCount() == 0) {
			finishGame();
		}
		
	}

	@Override
	public synchronized void updatePlayerLeft(Integer playerId) {
		for(ClientHandler handler: clients){
			if(handler.getId() == playerId){
				clients.remove(playerId);
			}
			handler.sendPlayerLeftNotification(playerId);
		}
		
	}

}
